<script setup>
import { ref, onMounted, computed } from 'vue'
import { sessionApi, pageRolesApi, oneRoleApi, selMenuBtnsApi, saveRoleApi, delRolesApi } from '@/commons/api'
import routes from '@/commons/router'
import Msg from '@/components/message'
import Confirm from '@/components/confirm'
import Pager from '@/components/pager/Pager.vue'
import { formatDate } from '@/commons/filter'
import { CScrollbar } from 'c-scrollbar'
import Loader from '@/components/loader/Loader.vue'

const loadShow = ref(false)

// 界面挂载前处理
onMounted(() => {
  // 获取用户会话信息
  checkAuth()
})

const procAuth = ref({
  addAuth: false,
  delAuth: false,
  edtAuth: false
})
// checkAuth 获取权限
const checkAuth = async () => {
  loadShow.value = true
  try {
    const res = await sessionApi()
    if (res.code === import.meta.env.VITE_SUCCESS_CODE) {
      const userBtnCode = res.data.btnCodes
      procAuth.value = {
        addAuth: userBtnCode.indexOf('1001010401') !== -1,
        delAuth: userBtnCode.indexOf('1001010402') !== -1,
        edtAuth: userBtnCode.indexOf('1001010403') !== -1
      }
      await selMenuBtns()
      await list(0, 1)
    } else {
      localStorage.removeItem("token")
      Msg({ kind: 'error', txt: res.msg })
      routes.replace('/login')
    }
    loadShow.value = false
  } catch (e) {
    loadShow.value = false
    Msg({ kind: 'error', txt: '系统错误，请联系管理员！' + e })
  }
}

const schObj = {
  keywords: '',
  offset: 0,
  limit: 20
}
const schRef = ref(schObj)
const total = ref(0)
const curPage = ref(1)
const roleList = ref([])
const hasData = ref(false)
// list 列表展示
const list = async (offset, cur) => {
  schRef.value.offset = offset || 0
  curPage.value = cur || 1
  hasData.value = false
  const res = await pageRolesApi(schRef.value)
  if(res.code === import.meta.env.VITE_SUCCESS_CODE && res.data) {
    hasData.value = true
    total.value = res.data.total
    roleList.value = res.data.list
    idList.value = []
    checkList.value = []
    allCheck.value = false
    res.data.list.forEach(() => {
      checkList.value.push(false)
    })
  }
}

// search 筛选
const schShow = ref(false)
const search = () => {
  schShow.value = !schShow.value
}

// clrSch 重置搜索框
const clrSch = () => {
  schRef.value = {
    keywords: '',
    offset: 0,
    limit: 20
  }
  list(0, 1)
}

// 选择效果实现
const idList = ref([])
const checkList = ref([])
const allCheck = ref(false)
// checkAll 全选
const checkAll = () => {
  idList.value = []
  checkList.value = []
  allCheck.value = !allCheck.value
  if(allCheck.value) {
    roleList.value.forEach(item => {
      idList.value.push(item.roleId)
      checkList.value.push(true)
    })
  } else {
    roleList.value.forEach(() => {
      checkList.value.push(false)
    })
  }
}
// checkCurId 单选
const checkCurId = (idx, roleId) => {
  if(!checkList.value[idx]) {
    idList.value.push(roleId)
  } else {
    idList.value.splice(idList.value.findIndex(id => id === roleId), 1)
  }
  checkList.value[idx] = !checkList.value[idx]
}

const roleForm = ref({
  roleId: '',
  roleName: '',
  roleCode: '',
  menuCodes: '',
  btnCodes: '',
  dataRole: 4
})

// 选中的菜单及按钮编号数组
let menuIdList = []
let btnIdList = []

// add 新增
const showModal = ref(false)
const add = () => {
  showModal.value = true
}
// update 修改
const update = async (roleId) => {
  loadShow.value = true
  try {
    const res = await oneRoleApi({roleId})
    if(res.code === import.meta.env.VITE_SUCCESS_CODE) {
      roleForm.value = res.data
      menuIdList = roleForm.value.menuCodes.split(',')
      btnIdList = roleForm.value.btnCodes ? roleForm.value.btnCodes.split(',') : []
      initVal(menuIdList, btnIdList)
      showModal.value = true
    } else {
      Msg({ kind: 'info', txt: '暂无内容' })
    }
    loadShow.value = false
  } catch (e) {
    loadShow.value = false
    Msg({ kind: 'error', txt: '系统错误，请联系管理员！' + e })
  }
}
// save 保存提交
const save = async () => {
  roleForm.value.menuCodes = menuIdList.join(",")
  roleForm.value.btnCodes = btnIdList.join(",")
  let roleName = roleForm.value.roleName
  let roleCode = roleForm.value.roleCode
  let menuCodes = roleForm.value.menuCodes
  if(roleName === '' || roleName.length > 50) {
    Msg({ kind: 'warn', txt: '角色的名称不能为空，且长度不超过50个字符！' })
    return
  } else if(roleCode === '' || roleCode.length > 30) {
    Msg({ kind: 'warn', txt: '角色的编码不能为空，且长度为30位的数字编码！' })
    return
  } else if(menuCodes === '' || menuCodes.length < 8) {
    Msg({ kind: 'warn', txt: '操作菜单不能为空！' })
    return
  }
  loadShow.value = true
  try {
    const res = await saveRoleApi(roleForm.value)
    if(res.code === import.meta.env.VITE_SUCCESS_CODE) {
      closeModal()
      await list(0, 1)
      Msg({ kind: 'success', txt: '恭喜您，角色信息保存成功！' })
    } else {
      Msg({ kind: 'error', txt: res.msg })
    }
    loadShow.value = false
  } catch (e) {
    loadShow.value = false
    Msg({ kind: 'error', txt: '系统错误，请联系管理员！' + e })
  }
}

// 菜单及按钮选中标识数组
// closeModal 关闭弹出层，并重置表单数据
const closeModal = () => {
  menuList.value.forEach(curMenu => {
    curMenu.chked = false
    if(curMenu.btnList && curMenu.btnList.length>0) {
      curMenu.btnList.forEach(curBtn => {
        curBtn.chked = false
      })
    }
  })
  menuIdList = []
  btnIdList = []
  menuChkAll.value = false
  showModal.value = false
  roleForm.value = {
    roleId: '',
    roleName: '',
    roleCode: '',
    menuCodes: '',
    btnCodes: '',
    dataRole: 4
  }
}

// deletes 删除角色
const deletes = async() => {
  if(!idList || idList.value.length===0) {
    Msg({ kind: 'warn', txt: '请至少选择一项再操作！' })
    return
  }
  Confirm('确定要删除选中的角色吗？').then(() => {
    delRole()
  }).catch(() => {
    Msg({ kind: 'info', txt: "取消处理选中的数据！" })
  })
}
// delRole 删除角色实现，分离出来防止调用时异步报错
const delRole = async () => {
  let roleIds = idList.value.join(',')
  loadShow.value = true
  try {
    const res = await delRolesApi({ roleIds })
    if(res.code === import.meta.env.VITE_SUCCESS_CODE) {
      await list(0, 1)
      Msg({ kind: 'success', txt: '恭喜您，角色信息删除成功！' })
    } else {
      Msg({ kind: 'error', txt: res.msg })
    }
    loadShow.value = false
  } catch (e) {
    loadShow.value = false
    Msg({ kind: 'error', txt: '系统错误，请联系管理员！' + e })
  }
}

// fmtDate 时间戳转时间
const fmtDate = computed(() => {
  return (time, kind) => {
    let date = new Date(time*1000)
    return formatDate(date, kind)
  }
})

// 所有菜单数组（包含按钮数组）
const menuList = ref([])
// selMenuBtns 获取菜单及按钮列表
const selMenuBtns = async () => {
  const res = await selMenuBtnsApi()
  if(res.code === import.meta.env.VITE_SUCCESS_CODE) {
    menuList.value = res.data
  }
}

// initVal 初始化菜单及按钮值选中
const initVal = (menuIdList, btnIdList) => {
  if(menuList.value && menuList.value.length > 0) {
    menuList.value.forEach(curMenu => {
      curMenu.chked = menuIdList.indexOf(curMenu.menuCode) !== -1
      if(curMenu.btnList && curMenu.btnList.length>0) {
        curMenu.btnList.forEach(curBtn => {
          curBtn.chked = btnIdList.indexOf(curBtn.btnCode) !== -1
        })
      }
    })
  }
}

// 全选标识
const menuChkAll = ref(false)
// chkAllMenu 全选
const chkAllMenu = () => {
  menuIdList = []
  btnIdList = []
  menuChkAll.value = !menuChkAll.value
  if(menuChkAll.value) { // 全选
    menuList.value.forEach(curMenu => {
      curMenu.chked = true
      menuIdList.push(curMenu.menuCode)
      if(curMenu.btnList && curMenu.btnList.length>0) {
        curMenu.btnList.forEach(curBtn => {
          btnIdList.push(curBtn.btnCode)
          curBtn.chked = true
        })
      }
    })
  } else { // 取消全选
    menuList.value.forEach(curMenu => {
      curMenu.chked = false
      if(curMenu.btnList && curMenu.btnList.length>0) {
        curMenu.btnList.forEach(curBtn => {
          curBtn.chked = false
        })
      }
    })
    menuIdList = []
    btnIdList = []
  }
}

// chkMenu 单选菜单
const chkMenu = (curMenu) => {
  if(menuIdList.indexOf(curMenu.menuCode) === -1) { // 选中
    menuIdList.push(curMenu.menuCode)
    // 同时将对应的按钮编码存储至按钮编号数组中
    if(curMenu.btnList && curMenu.btnList.length>0) {
      curMenu.btnList.forEach(curBtn => {
        btnIdList.push(curBtn.btnCode)
        curBtn.chked = true
      })
    }
  } else { // 取消选中
    // 将对应的编码从菜单编号数组中删除
    menuIdList.splice(menuIdList.findIndex(menuCode => menuCode === curMenu.menuCode), 1)
    // 将对应的编码从按钮编号数组中删除
    if(curMenu.btnList && curMenu.btnList.length>0) {
      curMenu.btnList.forEach(curBtn => {
        btnIdList.splice(btnIdList.findIndex(btnCode => btnCode === curBtn.btnCode), 1)
      })
    }
    // 同时将对应的按钮编码从按钮编号数组中删除
    if(curMenu.btnList && curMenu.btnList.length>0) {
      curMenu.btnList.forEach(curBtn => {
        curBtn.chked = false
      })
    }
  }
  curMenu.chked = !curMenu.chked
}
// chkBtn 单选按钮
const chkBtn = (curBtn) => {
  if(btnIdList.indexOf(curBtn.btnCode) === -1) {
    btnIdList.push(curBtn.btnCode)
  } else {
    btnIdList.splice(btnIdList.findIndex(btnCode => btnCode === curBtn.btnCode), 1)
  }
  curBtn.chked = !curBtn.chked
}

// chkKind 单选框选择显示
const chkKind = (idx) => {
  switch(idx) {
    case 1:
      roleForm.value.dataRole = 1
      break
    case 2:
      roleForm.value.dataRole = 2
      break
    case 3:
      roleForm.value.dataRole = 3
      break
    case 4:
      roleForm.value.dataRole = 4
      break
    default:
      roleForm.value.dataRole = 1
      break
  }
}

// fmtKind 种类转码
const fmtKind = computed(() => {
  return (kind) => {
    let str
    switch (kind) {
      case 1:
        str = '查看本人数据'
        break
      case 2:
        str = '查看本部门数据'
        break
      case 3:
        str = '查看本部门及以下数据'
        break
      case 4:
        str = '查看所有数据'
        break
      default:
        str = '其它'
        break
    }
    return str
  }
})
</script>

<template>
  <div class="a">
    <div class="b">
      <div class="c">
        <div v-if="procAuth.addAuth" class="btn-pi mr15" title="新增" @click="add"><i class="iconfont">&#xea2d;</i> 新增</div>
        <div v-if="procAuth.delAuth" class="btn-de mr15" title="删除" @click="deletes"><i class="iconfont">&#xea45;</i> 删除</div>
        <div class="btn-r mr15" title="筛选" @click="search"><i class="iconfont">&#xea49;</i></div>
        <div class="btn-r mr15" title="刷新" @click="list(0, 1)"><i class="iconfont">&#xea8c;</i></div>
      </div>
      <div class="d"><i class="iconfont">&#xeaaa;</i> 当前位置：工作台 > 系统管理 > 角色管理</div>
    </div>
    <div v-show="schShow" class="e">
      <div class="mr15 mt10"><input type="text" v-model="schRef.keywords" maxlength="30" placeholder="请输入关键字" class="sch-ipt" /></div>
      <div class="f mt10">
        <div class="btn-pi mr15" title="搜索" @click="list(0, 1)"><i class="iconfont">&#xea8e;</i> 搜索</div>
        <div class="btn-d" title="重置" @click="clrSch"><i class="iconfont">&#xea4f;</i> 重置</div>
      </div>
    </div>
    <div v-if="hasData">
      <table>
        <tbody>
          <tr>
            <th style="width: 5%;"><span @click="checkAll()" title="全选"><i :class="['iconfont', allCheck ? 'chked' : 'chk']" v-html="allCheck ? '&#xea3a;' : '&#xea46;'" /></span></th>
            <th style="width: 25%;">名称</th>
            <th style="width: 15%;">编码</th>
            <th style="width: 25%;">数据</th>
            <th style="width: 15%;">时间</th>
            <th style="width: 20%;">操作</th>
          </tr>
          <tr v-for="(curRole, index) in roleList" :key="curRole.roleId" class="tr-style">
            <td class="txt-center"><span @click="checkCurId(index, curRole.roleId)" title="选择"><i :class="['iconfont', checkList[index] ? 'chked' : 'chk']" v-html="checkList[index] ? '&#xe685;' : '&#xe686;'" /></span></td>
            <td>{{curRole.roleName}}</td>
            <td>{{curRole.roleCode}}</td>
            <td>{{fmtKind(curRole.dataRole)}}</td>
            <td class="txt-center">{{fmtDate(curRole.addTime, 2)}}</td>
            <td class="txt-center">
              <span v-if="procAuth.edtAuth" class="cl-warn" title="修改" @click="update(curRole.roleId)"><i class="iconfont">&#xea48;</i> 修 改</span>
            </td>
          </tr>
        </tbody>
      </table>
      <Pager v-if="hasData" :limit="schRef.limit" :total="total" :page="curPage" @turn="list" />
    </div>
    <div v-else class="no-data">暂无内容</div>

    <!-- 新增、修改弹出层 -->
    <transition name="fade-mod" appear>
      <div v-if="showModal" class="modal-backdrop">
        <c-scrollbar>
          <div class="modal" style="width: 800px;">
            <div class="modal-header">
              <div class="header-left"><i class="iconfont">&#xea54;</i> 保存角色信息</div>
              <div class="header-right" @click="closeModal()"><i class="iconfont fs22">&#xea7f;</i></div>
            </div>
            <div class="modal-body">
              <div>
                <div class="ipt-title"><span class="required">*</span>角色名称</div>
                <div><input type="text" v-model="roleForm.roleName" maxlength="50" placeholder="请输入角色名称" class="ipt" /></div>
              </div>
              <div>
                <div class="ipt-title"><span class="required">*</span>角色编码</div>
                <div><input type="text" v-model="roleForm.roleCode" maxlength="30" placeholder="请输入角色编码" class="ipt" /></div>
              </div>
              <div>
                <div class="ipt-title"><span class="required">*</span>数据权限</div>
                <div class="g">
                  <div class="cur h" @click="chkKind(1)"><i :class="['iconfont', roleForm.dataRole===1 ? 'chked' : 'chk']" v-html="roleForm.dataRole===1 ? '&#xe677;' : '&#xe678;'"></i> 查看本人数据</div>
                  <div class="cur h" @click="chkKind(2)"><i :class="['iconfont', roleForm.dataRole===2 ? 'chked' : 'chk']" v-html="roleForm.dataRole===2 ? '&#xe677;' : '&#xe678;'"></i> 查看本部门数据</div>
                  <div class="cur h" @click="chkKind(3)"><i :class="['iconfont', roleForm.dataRole===3 ? 'chked' : 'chk']" v-html="roleForm.dataRole===3 ? '&#xe677;' : '&#xe678;'"></i> 查看本部门及以下数据</div>
                  <div class="cur h" @click="chkKind(4)"><i :class="['iconfont', roleForm.dataRole===4 ? 'chked' : 'chk']" v-html="roleForm.dataRole===4 ? '&#xe677;' : '&#xe678;'"></i> 查看所有数据</div>
                </div>
              </div>
              <div>
                <div class="ipt-title"><span class="required">*</span>权限配置</div>
                <table>
                  <tbody>
                    <tr>
                      <th style="width: 40%;"><i @click="chkAllMenu()" :class="['iconfont', menuChkAll ? 'chked' : 'chk']" v-html="menuChkAll ? '&#xea3a;' : '&#xea46;'"></i> 菜单名称</th>
                      <th style="width: 60%;">操作按钮</th>
                    </tr>
                    <tr v-for="curMenu in menuList" :key="curMenu.menuId" class="tr-style">
                      <td>
                        <div class="cur" :style="{'padding-left': curMenu.level*20+'px'}" @click="chkMenu(curMenu)">
                          <i :class="['iconfont mr5', curMenu.chked ? 'chked' : 'chk']" v-html="curMenu.chked ? '&#xe685;' : '&#xe686;'"></i>
                          <span>{{curMenu.menuName}}[{{curMenu.menuCode}}]</span>
                        </div>
                      </td>
                      <td>
                        <span v-for="curBtn in curMenu.btnList" :key="curBtn.btnId" @click="chkBtn(curBtn)" class="i">
                          <i :class="['iconfont mr5', curBtn.chked ? 'chked' : 'chk']" v-html="curBtn.chked ? '&#xe685;' : '&#xe686;'"></i>
                          <span>{{curBtn.btnName}}</span>
                        </span>
                      </td>
                    </tr>
                  </tbody>
                </table>
              </div>
            </div>
            <div class="modal-footer">
              <div class="btn-pi mr15" @click="save"><i class="iconfont">&#xea90;</i> 保存</div>
              <div class="btn-d" @click="closeModal"><i class="iconfont">&#xea4f;</i> 取消</div>
            </div>
          </div>
        </c-scrollbar>
      </div>
    </transition>
    <loader :loadShow="loadShow" />
  </div>
</template>

<style scoped>
.a {padding: 10px;}
.b {padding: 0 20px 10px 20px; display: flex; display: -webkit-flex;}
.c {display: inline-flex; display: -webkit-inline-flex;}
.d {flex-grow: 1; text-align: right; padding-top: 10px; color: #666;}
.e {border: 1px dashed #DDD; padding: 5px 15px 15px 15px; display: flex; display: -webkit-flex; flex-wrap: wrap; margin-bottom: 10px;}
.f {display: inline-flex; display: -webkit-inline-flex;}
.g {display: flex; display: -webkit-flex;}
.h {margin: 10px;}
.i {padding-right: 20px; cursor: pointer;}
</style>